<template>
  <div>
    <h1>创建新账号</h1>
    <hr>
    <div>
      <p>钱包地址：{{ account.address }}</p>
      <p>钱包私钥：{{ account.privateKey }}</p>
      <p>账户余额：<span v-if="account.balance >= 0">{{ account.balance }} SeploliaETH</span></p>
      <p>
        <button @click="createAccount">创建账号</button> |
        <button :disabled="!account.hasAccount" @click="getAccountBalance">账号余额</button>
      </p>
    </div>
  </div>
  <div>
    <h1>测试钱包</h1>
    <hr>
    <div>
      <p>钱包地址：{{ testAccount.address }}</p>
      <p>钱包私钥：{{ testAccount.privateKey }}</p>
      <p>账户余额：{{ testAccount.balance }} EHT</p>
      <p>
        <button @click="getTestAccountBalance">获取账号余额</button>
      </p>
    </div>
  </div>
  <div>
    <h1>钱包转账</h1>
    <hr>
    <div>
      <p>
        <label>转账地址：</label>
        <input type="text" v-model="transactionInfo.fromAddress">
      </p>
      <p>
        <label>收款地址：</label>
        <input type="text" v-model="transactionInfo.toAddress">
      </p>
      <p>
        <label>钱包私钥：</label>
        <input type="text" v-model="transactionInfo.privateKey">
      </p>
      <p>
        <label>转账金额：</label>
        <input type="text" v-model="transactionInfo.amount"> ETH
      </p>
      <p>
        <button @click="signAndSendTransaction">执行转账</button>
      </p>
    </div>
  </div>

  <!-- 钱包地址：0xEcf85b92c4c4eF02f18570d7aaA9BA277bb98EdC
钱包私钥：0x018a45c459e99daf846fa17ac55b1a1cf2f5619253255f4cd9dbf45ce6fc8aea -->
</template>

<script setup>
// 导入模块
import Web3 from 'web3'
import { reactive, onMounted } from 'vue'
import { Chain, Common } from '@ethereumjs/common'
import { Transaction } from '@ethereumjs/tx'

// 初始化状态
const account = reactive({
  address: '',
  privateKey: '',
  balance: -1,
  hasAccount: false
})

// 测试账号
const testAccount = reactive({
  address: '0x4f8E261FcB17800Aba856c92EBe168De13dC3707',
  privateKey: '0xefa76d94e00ba8dca8219c9cd29a59a52e4d795a0d92c804d60ee1672c6c157b',
  balance: 0,
})

// 转账信息
const transactionInfo = reactive({
  fromAddress: '0x4f8E261FcB17800Aba856c92EBe168De13dC3707',
  toAddress: '0xEcf85b92c4c4eF02f18570d7aaA9BA277bb98EdC',
  privateKey: '0xefa76d94e00ba8dca8219c9cd29a59a52e4d795a0d92c804d60ee1672c6c157b',
  amount: 0.0001
})

// 创建Web3的实例
const web3 = new Web3(Web3.givenProvider || 'https://sepolia.infura.io/v3/33d1a84530fc40cd91090e1711a8841e')

// 执行创建账号
const createAccount = () => {
  // 生成熵值，32位16进制随机数
  const intropy = web3.utils.randomHex(32)
  // 创建账号
  const { address, privateKey } = web3.eth.accounts.create(intropy)
  // 状态模板
  account.address = address
  account.privateKey = privateKey

  account.hasAccount = true
}

// 获取账号余额
const getAccountBalance = async () => {
  const balance = await web3.eth.getBalance(account.address)
  account.balance = balance
}

// 获取测试账号余额
const getTestAccountBalance = async () => {
  const balance = await web3.eth.getBalance(testAccount.address)
  testAccount.balance = web3.utils.fromWei(balance)
}


const signAndSendTransaction = async () => {
  // 发送者的私钥, 去掉十六进制的 0x
  const privateKey = transactionInfo.privateKey.slice(2)
  // 发送者的以太坊地址
  const senderAddress = transactionInfo.fromAddress
  // 接收者的以太坊地址
  const recipientAddress = transactionInfo.toAddress
  // 转账金额
  const value = web3.utils.toWei(transactionInfo.amount.toString(), 'ether')

  const nonce = await web3.eth.getTransactionCount(senderAddress)
  const gasPrice = await web3.eth.getGasPrice()
  const gasLimit = 21000

  // 构造转账配置信息
  const rawTx = {
    nonce: web3.utils.toHex(nonce),
    gasPrice: web3.utils.toHex(gasPrice),
    gasLimit: web3.utils.toHex(gasLimit),
    to: recipientAddress,
    value: web3.utils.toHex(value),
  }

  // 创建转账对象 tx
  const common = new Common({ chain: Chain.Sepolia })
  const tx = Transaction.fromTxData(rawTx, { common })

  // 转账签名
  const serializedTx = tx.sign(Buffer.from(privateKey, 'hex')).serialize().toString('hex')

  // 发送转账信息
  try {
    const receipt = await web3.eth.sendSignedTransaction('0x' + serializedTx)
    console.log('Transaction receipt:', receipt)
  } catch (error) {
    console.error('Transaction error:', error)
  }
}

onMounted(() => {
  getTestAccountBalance()
})

</script>

<style scoped>
input {
  width: 60%;
}
</style>
